<?php
/* ムービーファイルパッケージを作成する
*
* http://www.nurs.or.jp/~calcium/wiki/index.php?FFMPEG%20USAGE
*/
class CreateMoviePKG {
	var $conf;
	
	var $ffmpegOption_swf2avi;
	var $ffmpegOption_movie;
	var $ffmpegOption;
	var $ffmpegOption_sound;
	var $mmfUtaOption;
	
	function CreateMoviePKG($conf){
		set_time_limit(0);
		$this->conf = $conf;
	}
	
	//ffmpegを起動
	function execFFmpeg($option){
		$cmd = '"'.$this->conf->ffmpeg.'"'.$option.' 2>&1';
		exec($cmd,$log);
		return $log;
	}

	//mmfUtaを起動
	function execMmfUta($option){
		$cmd = '"'.$this->conf->mmfUta.'"'.$option.' 2>&1';
		exec($cmd,$log);
		return $log;
	}
	
	//ディレクトリ内の一覧を取得・分割
	function create($flv,$movieid){
		//flvファイルがあるかチェック
		if(!file_exists($flv) ){
			//無かった
			return false;
		}
		
		//サイズチェック
		$flvsize_mb = filesize($flv)/1024000;
		if( ($flvsize_mb==0)||
			(($this->conf->flv_max_mb!=0)&&($flvsize_mb > $this->conf->flv_max_mb))
			){
			//サイズが0 or 大きかった
			return false;
		}
		
		$avi = $this->conf->cachedir.'/'.$movieid.'.avi';
		$this->ffmpegOption_swf2avi = ' -y -i [[FLV]] -vcodec flv -acodec copy '.$avi;
		$this->ffmpegOption_movie   = " -y -i [[FLV]] -s ".$this->conf->framesize." -aspect 4:3 -r ".$this->conf->fps." -b ".$this->conf->bps." ".$this->conf->basedir."/[[MOVIEID]]/%07d.jpg";
		if((strcmp($this->conf->audio_type,'wav')==0)||(strcmp($this->conf->audio_type,'')==0)){
			$this->ffmpegOption_sound = " -y -i [[FLV]] -ss [[SS]] -t [[T]] -acodec pcm_u8 -ac 1 -ar 8000 [[DIR]]/sound.wav";
		}
		else if(strcmp($this->conf->audio_type,'mp3')==0){
			//mp3
			$this->ffmpegOption_sound = " -y -i [[FLV]] -ss [[SS]] -t [[T]] -acodec libmp3lame -ac 1 -ar 8000 -ab 8k [[DIR]]/sound.mp3";
		}
		else if(strcmp($this->conf->audio_type,'amr-nb')==0){
			//amr-nb
			$this->ffmpegOption_sound = " -y -i [[FLV]] -ss [[SS]] -t [[T]] -acodec libamr_nb -ac 1 -ar 8000 -ab 4.75k -f amr [[DIR]]/sound.amr";
		}
		else if(strcmp($this->conf->audio_type,'amr-wb')==0){
			//amr-wb
			$this->ffmpegOption_sound = " -y -i [[FLV]] -ss [[SS]] -t [[T]] -acodec libamr_wb -ac 1 -ar 16000 -ab 23.05k -f amr [[DIR]]/sound.amr-wd";
		}
		else if(strcmp($this->conf->audio_type,'mmf')==0){
			$this->ffmpegOption_sound = ' -y -i [[FLV]] -ss [[SS]] -t [[T]] -acodec pcm_u8 -ac 1 -ar 8000 [[DIR]]/sound.wav';
			$this->mmfUtaOption = ' -a [[DIR]]/sound.wav';
		}
		
		if(strcmp($movieid,"")==0) $movieid = "moviepkg";

		//出力先フォルダがあるかチェック・無ければ作る
		if(!is_dir($this->conf->basedir)){
			@mkdir($this->conf->basedir);
		}
		
		//出力フォルダ作成
		$outdir = $this->conf->basedir . "/".$movieid;
		if( is_dir( $outdir ) ){
			//既に有った場合 処理を実行しない
			return false;
		}
		@mkdir($outdir,0777);
		
		//swfの場合cws2fwsを通す
		if(strpos($movieid,'nm')!==false){
			$flv_org = $flv.'org';
			rename($flv,$flv_org);
			$cmd = $this->conf->cws2fws.' '.$flv_org.' '.$flv;
			exec($cmd);
			unlink($flv_org);
			
			//AVIに変更
			$option = str_replace(array('[[FLV]]'),
								  array($flv),
								  $this->ffmpegOption_swf2avi);
			$this->execFFmpeg($option);
			
			//$flvをaviのパスに書き換え
			$flv = $this->conf->cachedir.'/'.$movieid.".avi";
			
			if(!file_exists($flv)){
				//aviファイルの出力に失敗？
				return false;
			}
			
			//連番 jpg 作成
			$log = $this->outJpegs($flv,$movieid);
			
			//ログの中から Duration: 00:04:13.0, の値を取得する
			$pattern = "/Duration:([^,]+),/";
			preg_match($pattern,implode('',$log),$matches);
			$duration_hms = split(':',trim($matches[1])); //00:04:13.0
			$duration = mktime($duration_hms[0],$duration_hms[1],$duration_hms[2]) - mktime(0,0,0)-1;

			//音声の長さ分だけループして連番でjpg作成
			$img_cnt = 1; //0000001.jpg
			for($i=0;$i<$duration;$i++){
				//1秒間にfps毎
				for($j=0;$j<$this->conf->fps;$j++){
					$img_cnt++;
					$img_name = sprintf("%07d.jpg",$img_cnt);
					copy($this->conf->basedir.'/'.$movieid.'/0000001.jpg',$this->conf->basedir.'/'.$movieid.'/'.$img_name);
				}
			}
		}
		else{
			//連番 jpg 作成
			$this->outJpegs($flv,$movieid);
		}
		
		//一覧取得
		$tree = array(); //ソート用の配列
		$d = dir($outdir);
		while (false !== ($entry = $d->read())) {
			//カレントと上位階層を除外
            if( $entry != "." && $entry != ".." )
            {
		   		//$path = $this->conf->basedir."/".$entry;
		   		$path = $outdir."/".$entry;
		   		if( is_file($path) ){
		   			$tree[ $entry ] = $path;
		   		}
			}
		}
		$d->close();
		//ソート
		uasort( $tree, "strcmp" );

		//$this->conf->maxIndex 個づつにフォルダに別ける
		$filelist = "";
		$index = 1;
		$outdir_index = 1;
		
		$newfilesize = 0;
		$oldfilesize = 0;
		$oldkey = 0;

		//最大再生時間に対するjarファイルの数を求める 0:制限無し
		$max_outdir_index = ($this->conf->max_total_time_sec==0)?0:($this->conf->max_total_time_sec/$this->conf->n)+1;
		
		foreach( $tree as $key => $filepath ){
			//最大再生時間チェック
			if(($max_outdir_index!=0)&&($outdir_index>=$max_outdir_index)){
				//最大値になった
				//残りファイル削除
				@unlink($filepath);
				continue;
			}
			
			//フォルダがあるかチェック
			$outdir = $this->conf->basedir . "/".$movieid."/img" . $outdir_index;
			if( !is_dir( $outdir ) ){
				//無かった場合作成
				@mkdir($outdir,0777);
			}
			//移動先ファイルパス作成
			$newfile = $outdir . "/" . $key;
			
			//拡張子を削除
			$tmpkey = str_replace(".jpg","",$key);

			//今回処理するファイルのサイズ
			$newfilesize = filesize($filepath);
			
			//一回前のファイルサイズと今回処理するファイルサイズを比較
			//TODO ファイルサイズの比較でうまくいく間引ける？
			if( ($oldfilesize!=0) && ($oldfilesize==$newfilesize) ){
				//同じだった場合、前回の$keyをリストへ設定
				$tmpkey = $oldkey;
				//コピーをしない
			}
			else {
				if(strcmp($this->conf->img_type,'jpg')==0){
					//GDを通す ついでにコピー
					$this->gd($filepath,$newfile);
				}
				else {
					//ハフマンテーブル・フレーム・タイプ取得＆出力

					if($index == 1){
						$soffile = $outdir . "/sof.bin";
						$dhtfile = $outdir . "/dht.bin";
						getSOFDHT($filepath, $soffile, $dhtfile);
					}

					//ハフマンテーブル・フレーム・タイプ・exif・コメント削除
					jpg_clean($filepath, $newfile);
				}
				
				//古いファイルサイズを更新
				$oldfilesize = $newfilesize;
				$oldkey      = $tmpkey;
			}
			
			//ファイルリストに $key の値を追加
			$filelist .= $tmpkey . "\n";
			
			//元ファイル削除
			@unlink($filepath);
			
			$index++;
			if($index > $this->conf->maxIndex ){
				
				//インデックスファイルを出力
				$filename = $outdir . "/filelist.txt";
				file_put_contents ( $filename, $filelist);
				$filelist = "";
				
				//サウンド出力
				$this->outAudio($outdir_index,$flv,$outdir);
				
				//mmfに変換
				$this->wav2mmf($outdir);
				
				//jarで圧縮
				$this->outJar($movieid,$outdir,$outdir_index);
				
				//TODO 圧縮したフォルダは削除
				$this->deleteDir($outdir);
				
				$outdir_index++;
				$index = 1;
				
				$oldfilesize = 0;
			}
		}
		
		if(($max_outdir_index==0)||($outdir_index<$max_outdir_index)){
			//半端な出力をjar圧縮
			if($index <= $this->conf->maxIndex ){
				$outdir = $this->conf->basedir . "/".$movieid."/img" . $outdir_index;
				
				//インデックスファイルを出力
				$filename = $outdir . "/filelist.txt";
				@file_put_contents ( $filename, $filelist);
				$filelist = "";
				
				//サウンド出力
				$this->outAudio($outdir_index,$flv,$outdir);
				
				//mmfに変換
				$this->wav2mmf($outdir);
				
				//jarで圧縮
				$this->outJar($movieid,$outdir,$outdir_index);
				
				//TODO 圧縮したフォルダは削除
				$this->deleteDir($outdir);
			}
		}
		
		echo "success!!\n";
	}
	
	//連番jpg出力
	function outJpegs($flv,$movieid){
		//[[MOVIEID]] を置き換え
		$option = str_replace(array('[[FLV]]','[[MOVIEID]]'),
							  array($flv,$movieid),
							  $this->ffmpegOption_movie);
		//ffmpegを実行
		$log = $this->execFFmpeg($option);
		
		return $log;
	}
	
	//jarファイル出力
	function outJar($movieid,$outdir,$outdir_index){
		$jarpath = $this->conf->basedir . "/".$movieid."/img".$outdir_index.".jar";
		$cmd = "\"" . $this->conf->jar ."\" cfM ".$jarpath." -C ".$outdir." .";
		exec( $cmd );
	}
	
	//サウンドファイル出力
	function outAudio($outdir_index,$flv,$outdir){
		$t = $this->conf->maxIndex/$this->conf->fps;
		$ss = ($outdir_index-1)*$t;
		$option = str_replace(array('[[FLV]]','[[SS]]','[[T]]','[[DIR]]'),
							  array($flv,$ss,$t,$outdir),
							  $this->ffmpegOption_sound);
		$this->execFFmpeg($option);
	}
	
	//WAVをMMFに変換
	function wav2mmf($outdir){
		if(strcmp($this->conf->audio_type,'mmf')==0){
			$option = str_replace(array('[[DIR]]'),array($outdir),$this->mmfUtaOption);
			$this->execMmfUta($option);
			//WAVファイル削除
			unlink($outdir.'/sound.wav');
		}
	}
	
	//ffmpegで出力したjpegをGDに通す(X01Tの為に)
	function gd($src,$dist){
		$img = @imagecreatefromjpeg($src);
		imagejpeg($img,$dist);
		imagedestroy($img);
	}
	
	// ディレクトリ削除
	function deleteDir($rootPath){
		if(is_dir($rootPath)){
			$strDir = opendir($rootPath);
			while($strFile = readdir($strDir)){
				//ディレクトリでない場合のみ
				if($strFile != '.' && $strFile != '..'){
					@unlink($rootPath.'/'.$strFile);
				}
			}
			closedir($strDir);
			rmdir($rootPath);
		}
	}

	function var_dump( $msg ){
		echo "<per>\n";
		var_dump( $msg );
		echo "</per>\n";
	}
}
?>